package com.linkstec.mot.util;

import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;

import com.alibaba.fastjson.JSON;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class RedisTemplateUtil {
	// private static Logger logger = LoggerFactory.getLogger(RedisUtil.class);

	private static StringRedisTemplate redisTemplate;

	static {
		redisTemplate = SpringContextUtil.getBean("redisTemplate");
	}

	/**
	 * 设置键值对
	 * 
	 * @param key
	 * @param value
	 */
	public static void setObject(String key, Object value) {
		String strValue = null;
		if (value != null) {
			strValue = JSON.toJSONString(value);
		}
		redisTemplate.opsForValue().set(key, strValue);
	}

	/**
	 * 设置键值对
	 * 
	 * @param key
	 * @param value
	 */
	public static void setExpire(final String key, final Object value,
			final Long expireTime) {
		redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection con)
					throws DataAccessException {
				String strVal = "";
				if (value != null) {
					strVal = JSON.toJSONString(value);
				}
				con.setEx(key.getBytes(), expireTime, strVal.getBytes());
				return null;
			}
		});
	}

	/**
	 * 根据key或者值
	 * 
	 * @param key
	 * @param clazz
	 * @return
	 */
	public static <T> T getObject(String key, Class clazz) {
		T value = null;
		String strValue = (String) redisTemplate.opsForValue().get(key);
		if (strValue != null) {
			value = (T) JSON.parseObject(strValue, clazz);
		}

		return value;
	}

	/**
	 * 向阻塞队列加入数据
	 * 
	 * @param key
	 * @param value
	 */
	public static void lPush(String key, Object value) {
		String strValue = null;
		if (value != null) {
			strValue = JSON.toJSONString(value);
		}
		redisTemplate.opsForList().leftPush(key, strValue);
	}

	/**
	 * 阻塞方式获取队列数据
	 * 
	 * @param key
	 * @param clazz
	 * @return
	 */
	public static <T> T bRPop(final String key, final Class clazz) {
		return redisTemplate.execute(new RedisCallback<T>() {
			@Override
			public T doInRedis(RedisConnection con) throws DataAccessException {
				String strVal = String.valueOf(con.bRPop(0, key.getBytes())
						.get(0));
				return (T) JSON.parseObject(strVal, clazz);
			}
		});
	}

	/**
	 * 获取队列大小
	 * 
	 * @param key
	 * @return
	 */
	public static Long getQueueSize(String key) {
		return redisTemplate.opsForList().size(key);
	}

	/**
	 * 设置缓存
	 * 
	 * @param key
	 * @param map
	 */
	public static void batchPutHash(String key, Map<String, String> map) {
		redisTemplate.opsForHash().putAll(key, map);
	}

	/**
	 * 获取缓存的某个key的值
	 * 
	 * @param key
	 * @param hashKey
	 * @return
	 */
	public static String hget(String key, String hashKey) {
		return (String) redisTemplate.opsForHash().get(key, hashKey);
	}

	/**
	 * 获取整个缓存
	 * 
	 * @param key
	 * @return
	 */
	public static Map<String, String> getHashMap(String key) {
		Set<Object> keys = redisTemplate.opsForHash().keys(key);
		return (Map<String, String>) redisTemplate.opsForHash().multiGet(key,
				keys);
	}

	public static long getIncrementId(String key) {
		return redisTemplate.opsForValue().increment(key, 1);
	}

	/**
	 * 删除某个键值
	 * 
	 * @param key
	 */
	public static void delete(String key) {
		redisTemplate.delete(key);
	}

	/**
	 * 得不到锁立即返回0，得到锁返回设置的超时时间
	 * 
	 * @param key
	 * @param lockTimeOut
	 * @return
	 */
	public static long tryLock(final String key, final long lockTimeOut) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection con)
					throws DataAccessException {
				long expireTime = System.currentTimeMillis() + lockTimeOut + 1;
				if (con.setNX(key.getBytes(), String.valueOf(expireTime)
						.getBytes())) {
					return expireTime;
				} else {
					String curLockTimeStr = new String(con.get(key.getBytes()));
					if (StringUtils.isNotBlank(curLockTimeStr)
							|| System.currentTimeMillis() > Long
									.valueOf(curLockTimeStr)) {
						expireTime = System.currentTimeMillis() + lockTimeOut
								+ 1;
						curLockTimeStr = new String(con.getSet(key.getBytes(),
								String.valueOf(expireTime).getBytes()));
						if (StringUtils.isBlank(curLockTimeStr)
								|| System.currentTimeMillis() > Long
										.valueOf(curLockTimeStr)) {
							return expireTime;
						} else {
							return 0L;
						}
					} else {
						return 0L;
					}
				}
			}
		});
	}

	public static void unLock(final String key, final long expireTime) {
		redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection con)
					throws DataAccessException {
				if (System.currentTimeMillis() - expireTime > 0) {
					return null;
				}
				String curLockTimeStr = String.valueOf(con.get(key.getBytes()));

				if (StringUtils.isNotBlank(curLockTimeStr)
						&& Long.valueOf(curLockTimeStr) > System
								.currentTimeMillis()) {
					con.del(key.getBytes());
				}
				return null;
			}
		});
	}
	// public static void main(String[] args) {
	// // TODO Auto-generated method stub
	// ApplicationContext ac = new
	// ClassPathXmlApplicationContext("applicationContext-common.xml");
	// StringRedisTemplate redisTemplate = (StringRedisTemplate)
	// ac.getBean("redisTemplate");
	// redisTemplate.opsForValue().set("test", "Hello World!");
	// Long beginTime = System.currentTimeMillis();
	// for(int i = 0; i < 100; i++)
	// {
	// redisTemplate.opsForValue().get("test");
	// }
	// System.out.println("costs " + (System.currentTimeMillis() - beginTime) +
	// " ms.");
	//
	// System.out.println("get ID:" +
	// redisTemplate.opsForValue().increment("testId", 1L));
	// redisTemplate.delete("test");
	// redisTemplate.delete("testId");
	// }

}
